//
//Copyright 2001-2004 Stottler Henke Associates, Inc.
//All Rights Reserved.
////////////////////////////////////////////////////////////////////////////////

package com.stottlerhenke.simbionic.engine.parser;

import com.stottlerhenke.simbionic.engine.*;
import com.stottlerhenke.simbionic.engine.file.SB_StreamReader;
import com.stottlerhenke.simbionic.api.*;
import com.stottlerhenke.simbionic.api.SB_Param;
/**
 * Represents a single variable of type integer.
 */
public class SB_VarInteger extends SB_Variable
{

  public SB_VarInteger() {
    _parameterValue = new SB_Param(0);
  }
  
  public SB_VarInteger(int value){
    _parameterValue = new SB_Param(value);
  }
  
  public SB_VarInteger(SB_VarInteger var2) throws SB_Exception
  {
    Copy(var2);
  }
  
  private void Copy(SB_VarInteger var) throws SB_Exception
  {
    _parameterValue = new SB_Param(var.GetValue());
  }
  
  public SB_VarType GetType() { return SB_VarType.kInteger; }
  
  public void setSB_Param(SB_Param newParam) throws SB_Exception
  {
    newParam.getInteger();
    
    _parameterValue = newParam;
  }
  
  private void Free(){
    // nothing to free
  }

  public void SetValue(int value){
    _parameterValue.setInteger(value);
  }

  public int GetValue() throws SB_Exception
  {
    return _parameterValue.getInteger();
  }
  
  public void load(SB_StreamReader reader,SB_SingletonBook book)
		throws SB_Exception
	{
    // this is really a pascal-style string
    String expr = reader.readPString();

    SB_Expression parsedExp = (SB_Expression)book.getParser().Parse(expr);

    // evaluating the expression without passing in an entity or execution frame is
    // only safe because the expression contains only constants!
    SB_Variable expValue = parsedExp.Evaluate(null, null);
    if (expValue.GetType() == SB_VarType.kFloat)
    {
      _parameterValue.setInteger(  (int)((SB_VarFloat)expValue).GetValue() );
    }
    else if (expValue.GetType() == SB_VarType.kInteger)
    {
      _parameterValue.setInteger( ((SB_VarInteger)expValue).GetValue() );;
    }
    else
      throw new SB_Exception("Illegal initial value " + expr +" for integer variable.");
  }
  
  public SB_VarInteger opAssign(SB_VarInteger var) throws SB_Exception
  {
    if (this != var) {
        Free();
        Copy(var);
     }
     return this;
  }

  public SB_Variable Clone() throws SB_Exception{
    return new SB_VarInteger(this);
  }
  
  public static int GET_INTEGER(SB_Variable var) throws SB_Exception
  {
    return ((SB_VarInteger)var).GetValue();
  }
  
  public String toString()
  { 
    try
    {
      return Integer.toString(GetValue());
    }
    catch(SB_Exception ex)
    {
      return ex.toString();
    }
  }
  
  public boolean bool() throws SB_Exception
  {
    //FATAL( false, "Invalid operation on SB_Variable base class");
    return GetValue() != 0;
  }

  public SB_Variable opSUB(SB_Variable arg2) throws SB_Exception  
  {
    SB_Variable result = null;

    if (arg2.GetType() == SB_VarType.kInteger)
      result = new SB_VarInteger( GetValue() - GET_INTEGER(arg2) );
    else if(arg2.GetType() == SB_VarType.kFloat)
      result = new SB_VarFloat( GetValue() - SB_VarFloat.GET_FLOAT(arg2) );

    return result;

  }

  public SB_Variable opNOT() throws SB_Exception  {
    return new SB_VarBoolean( GetValue() == 0 );
  }
  
  public SB_Variable opNEG() throws SB_Exception{
    return new SB_VarInteger( -GetValue() );
  }
  
  public SB_Variable opADD( SB_Variable arg2) throws SB_Exception  {
    SB_Variable result = null;

    if(arg2.GetType() == SB_VarType.kInteger)
      result = new SB_VarInteger( GetValue() + SB_VarInteger.GET_INTEGER(arg2) );
    else if(arg2.GetType() == SB_VarType.kFloat)
      result = new SB_VarFloat( GetValue() + SB_VarFloat.GET_FLOAT(arg2) );
    else if(arg2.GetType() == SB_VarType.kString) // returns a concatenated string
    {
      String workStr =  GetValue() + SB_VarString.GET_STRING(arg2);
      result = new SB_VarString( workStr );
    }else
      result = null;
    return result;

  }

  public SB_Variable opMUL( SB_Variable arg2) throws SB_Exception  {
    SB_Variable result = null;

    if(arg2.GetType() == SB_VarType.kInteger)
      result = new SB_VarInteger( GetValue() * SB_VarInteger.GET_INTEGER(arg2) );
    else if(arg2.GetType() == SB_VarType.kFloat)
      result = new SB_VarFloat( GetValue() * SB_VarFloat.GET_FLOAT(arg2) );
    else if(arg2.GetType() == SB_VarType.kVector){
      SB_Vector vector = SB_VarVector.GET_VECTOR(arg2);
      result = new SB_VarVector( vector.x * GetValue(),
                                 vector.y * GetValue(),
                                 vector.z * GetValue() );
    }
    else result = null;
    return result;

  }

  public SB_Variable opDIV( SB_Variable arg2) throws SB_Exception  {
    SB_Variable result = null;

    if(arg2.GetType() == SB_VarType.kInteger)
      result = new SB_VarInteger( GetValue() / SB_VarInteger.GET_INTEGER(arg2) );
    else if(arg2.GetType() == SB_VarType.kFloat)
      result = new SB_VarFloat( GetValue() / SB_VarFloat.GET_FLOAT(arg2) );
    else result = null;

    return result;

  }

  public SB_Variable opEXP( SB_Variable arg2) throws SB_Exception  {
    SB_Variable result = null;

    if(arg2.GetType() == SB_VarType.kInteger)
      result = new SB_VarInteger((int) Math.pow(GetValue(), SB_VarInteger.GET_INTEGER(arg2)) );
    else if(arg2.GetType() == SB_VarType.kFloat)
      result = new SB_VarFloat( (float)Math.pow(GetValue(), SB_VarFloat.GET_FLOAT(arg2)) );
    else
      result = null;

    return result;
  }

  public SB_Variable opMOD( SB_Variable arg2) throws SB_Exception  {
    SB_Variable result = null;

    if(arg2.GetType() == SB_VarType.kInteger)
      result = new SB_VarInteger( GetValue() % SB_VarInteger.GET_INTEGER(arg2) );
    else if(arg2.GetType() == SB_VarType.kFloat)
      result = new SB_VarFloat( GetValue() % SB_VarFloat.GET_FLOAT(arg2) );//fmod() in C++
    else
      result = null;
    return result;

  }

  public SB_Variable opLSS( SB_Variable arg2) throws SB_Exception  {
    SB_Variable result = null;

    if(arg2.GetType() == SB_VarType.kInteger)
      result = new SB_VarBoolean( GetValue() < SB_VarInteger.GET_INTEGER(arg2) );
    else if(arg2.GetType() == SB_VarType.kFloat)
      result = new SB_VarBoolean( GetValue() < SB_VarFloat.GET_FLOAT(arg2) );
    else
      result = null;
    return result;

  }

  public SB_Variable opGRT( SB_Variable arg2) throws SB_Exception  {
    SB_Variable result = null;

   if(arg2.GetType() == SB_VarType.kInteger)
     result = new SB_VarBoolean( GetValue() > SB_VarInteger.GET_INTEGER(arg2) );
   else if(arg2.GetType() == SB_VarType.kFloat)
     result = new SB_VarBoolean( GetValue() > SB_VarFloat.GET_FLOAT(arg2) );
   else
     result = null;
   return result;

  }

  public SB_Variable equals( SB_Variable arg2) throws SB_Exception  {
    SB_Variable result = null;

    if(arg2.GetType() == SB_VarType.kInteger)
      result = new SB_VarBoolean( GetValue() == SB_VarInteger.GET_INTEGER(arg2) );
    else if(arg2.GetType() == SB_VarType.kFloat)
      result = new SB_VarBoolean( GetValue() == SB_VarFloat.GET_FLOAT(arg2) );
    else if(arg2.GetType() == SB_VarType.kInvalid)
      result = new SB_VarBoolean( false );
    else
      result = null;
    return result;

  }

  public SB_Variable opNOTEq( SB_Variable arg2) throws SB_Exception  {
    SB_Variable result = null;

    if(arg2.GetType()== SB_VarType.kInteger)
      result = new SB_VarBoolean( GetValue() != SB_VarInteger.GET_INTEGER(arg2) );
    else if(arg2.GetType() == SB_VarType.kFloat)
      result = new SB_VarBoolean( GetValue() != SB_VarFloat.GET_FLOAT(arg2) );
    else if(arg2.GetType() == SB_VarType.kInvalid)
      result = new SB_VarBoolean( true );
   else
     result = null;
    return result;

  }

  public SB_Variable opLSSEq( SB_Variable arg2) throws SB_Exception  {
    SB_Variable result = null;

    if(arg2.GetType() == SB_VarType.kInteger)
      result = new SB_VarBoolean( GetValue() <= SB_VarInteger.GET_INTEGER(arg2) );
    else if(arg2.GetType() == SB_VarType.kFloat)
      result = new SB_VarBoolean( GetValue() <= SB_VarFloat.GET_FLOAT(arg2) );
    else
      result = null;
    return result;

  }

  public SB_Variable opGRTEq( SB_Variable arg2) throws SB_Exception  {
    SB_Variable result = null;

    if(arg2.GetType() == SB_VarType.kInteger)
      result = new SB_VarBoolean( GetValue() >= SB_VarInteger.GET_INTEGER(arg2) );
    else if(arg2.GetType() == SB_VarType.kFloat)
      result = new SB_VarBoolean( GetValue() >= SB_VarFloat.GET_FLOAT(arg2) );
    else
      result = null;
    return result;

  }

  public SB_Variable opAND( SB_Variable arg2) throws SB_Exception  {
    SB_Variable result = null;

    if (arg2.GetType() == SB_VarType.kInteger)
      result = new SB_VarBoolean( GetValue() != 0 && SB_VarInteger.GET_INTEGER(arg2) != 0);
    else if(arg2.GetType() == SB_VarType.kFloat)
      result = new SB_VarBoolean( GetValue() != 0&& SB_VarFloat.GET_FLOAT(arg2) != 0);
    else
      result = null;
    return result;

  }

  public SB_Variable opOr( SB_Variable arg2) throws SB_Exception  {
    SB_Variable result = null;

    if (arg2.GetType() == SB_VarType.kInteger)
      result = new SB_VarBoolean( GetValue() != 0 || SB_VarInteger.GET_INTEGER(arg2) != 0 );
    else if(arg2.GetType() == SB_VarType.kFloat)
      result = new SB_VarBoolean( GetValue() != 0|| SB_VarFloat.GET_FLOAT(arg2) != 0 );

    return result;

  }

}